package com.mzw.project.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mzw.mzwclientsdk.client.MzwClient;
import com.mzw.mzwclientsdk.model.Message;
import com.mzw.mzwclientsdk.model.SongName;
import com.mzw.mzwclientsdk.model.Word;
import com.mzw.mzwcommon.model.entity.InterfaceInfo;
import com.mzw.mzwcommon.model.entity.User;
import com.mzw.project.annotation.AuthCheck;
import com.mzw.project.common.*;
import com.mzw.project.constant.InterfaceInfoConstant;
import com.mzw.project.exception.BusinessException;
import com.mzw.project.model.dto.interfaceinfo.*;
import com.mzw.project.constant.CommonConstant;

import com.mzw.project.model.enums.InterfaceInfoStatusEnum;
import com.mzw.project.service.InterfaceInfoService;
import com.mzw.project.service.UserService;
import com.yupi.yucongming.dev.client.YuCongMingClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 接口管理
 *
 * @author mzw
 */
@RestController
@RequestMapping("/interfaceInfo")
@Slf4j
public class InterfaceInfoController {

    @Resource
    private InterfaceInfoService interfaceInfoService;

    @Resource
    private UserService userService;

    @Resource
    private MzwClient mzwClient;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private CacheClient cacheClient;

    @Resource
    private YuCongMingClient yuCongMingClient;


    /**
     * 创建
     *
     * @param interfaceInfoAddRequest 增加接口所需参数
     * @param request 请求信息
     * @return
     */
    @PostMapping("/add")
    public BaseResponse<Long> addInterfaceInfo(@RequestBody InterfaceInfoAddRequest interfaceInfoAddRequest
            , HttpServletRequest request) {
        // 请求参数是否存在值
        if (interfaceInfoAddRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 复制属性信息
        InterfaceInfo interfaceInfo = new InterfaceInfo();
        BeanUtils.copyProperties(interfaceInfoAddRequest, interfaceInfo);
        // 校验，通过validInterfaceInfo 方法进行校验
        interfaceInfoService.validInterfaceInfo(interfaceInfo);
        // 获取当前登录用户
        User loginUser = userService.getLoginUser(request);
        // 保存接口创建人信息
        interfaceInfo.setUserId(loginUser.getId());
        // 增加一条接口
        boolean result = interfaceInfoService.save(interfaceInfo);
        // 判断是否增加成功
        if (!result) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        // 返回接口id。
        long newInterfaceInfoId = interfaceInfo.getId();
        return ResultUtils.success(newInterfaceInfoId);
    }

    /**
     * 删除
     *
     * @param deleteRequest 删除接口所需参数，只需一个id即可。
     * @param request 请求信息
     * @return
     */
    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteInterfaceInfo(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        // 判断请求参数是否有效
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 获取当前登录用户id
        User user = userService.getLoginUser(request);
        long id = deleteRequest.getId();
        // 判断接口是否存在
        InterfaceInfo oldInterfaceInfo = interfaceInfoService.getById(id);
        // 如果不存在，抛出异常
        if (oldInterfaceInfo == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        // 仅本人或管理员可删除
        if (!oldInterfaceInfo.getUserId().equals(user.getId()) && !userService.isAdmin(request)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        // 执行删除功能
        boolean b = interfaceInfoService.removeById(id);
        // 返回删除结果
        return ResultUtils.success(b);
    }

    /**
     * 更新
     *
     * @param interfaceInfoUpdateRequest 更新接口所需信息
     * @param request 请求信息
     * @return
     */
    @PostMapping("/update")
    public BaseResponse<Boolean> updateInterfaceInfo(@RequestBody InterfaceInfoUpdateRequest interfaceInfoUpdateRequest,
                                                     HttpServletRequest request) {
        // 判断请求参数是否有效
        if (interfaceInfoUpdateRequest == null || interfaceInfoUpdateRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 创建一个接口对象
        InterfaceInfo interfaceInfo = new InterfaceInfo();
        // 将更新后的内容复制到创建的接口对象中
        BeanUtils.copyProperties(interfaceInfoUpdateRequest, interfaceInfo);
        // 参数校验，其实就是对接口长度进行校验
        interfaceInfoService.validInterfaceInfo(interfaceInfo);
        // 得到当前登录用户
        User user = userService.getLoginUser(request);
        // 获取修改接口信息id
        long id = interfaceInfoUpdateRequest.getId();
        // 判断修改接口是否存在
        InterfaceInfo oldInterfaceInfo = interfaceInfoService.getById(id);
        if (oldInterfaceInfo == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        // 仅本人或管理员可修改
        if (!oldInterfaceInfo.getUserId().equals(user.getId()) && !userService.isAdmin(request)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        // 进行更新
        boolean result = interfaceInfoService.updateById(interfaceInfo);
        // 删除缓存
        String key = InterfaceInfoConstant.CACHE_INTERFACEINFO_KEY + id;
        stringRedisTemplate.delete(key);
        //返回结果
        return ResultUtils.success(result);
    }

    /**
     * 根据 id 获取
     *
     * @param id
     * @return
     */
    @GetMapping("/get")
    public BaseResponse<InterfaceInfo> getInterfaceInfoById(long id) {
        // 解决缓存穿透
        InterfaceInfo interfaceInfo = cacheClient
                .queryWithPassThrough("cache:interfaceInfo", id,
                        InterfaceInfo.class, interfaceInfoId -> interfaceInfoService.getById(interfaceInfoId),
                        30L, TimeUnit.MINUTES);

        // 互斥锁解决缓存击穿
        // Shop shop = cacheClient
        //         .queryWithMutex(CACHE_SHOP_KEY, id, Shop.class, this::getById, CACHE_SHOP_TTL, TimeUnit.MINUTES);

        // 逻辑过期解决缓存击穿
        // Shop shop = cacheClient
        //         .queryWithLogicalExpire(CACHE_SHOP_KEY, id, Shop.class, this::getById, 20L, TimeUnit.SECONDS);

//        InterfaceInfo interfaceInfo = cacheClient.queryWithLogicalExpire("cache:interfaceInfo", id,
//                InterfaceInfo.class, interfaceInfoId -> interfaceInfoService.getById(interfaceInfoId),
//                30L, TimeUnit.MINUTES);
        if (interfaceInfo == null) {
            return ResultUtils.error(ErrorCode.NOT_FOUND_ERROR, "接口不存在");
        }
        // 7.返回
        return ResultUtils.success(interfaceInfo);
    }

    /**
     * 获取列表（仅管理员可使用）
     *
     * @param interfaceInfoQueryRequest
     * @return
     */
    @AuthCheck(mustRole = "admin")
    @GetMapping("/list")
    public BaseResponse<List<InterfaceInfo>> listInterfaceInfo(InterfaceInfoQueryRequest interfaceInfoQueryRequest) {
        InterfaceInfo interfaceInfoQuery = new InterfaceInfo();
        if (interfaceInfoQueryRequest != null) {
            BeanUtils.copyProperties(interfaceInfoQueryRequest, interfaceInfoQuery);
        }
        QueryWrapper<InterfaceInfo> queryWrapper = new QueryWrapper<>(interfaceInfoQuery);
        // 获取全部接口信息
        List<InterfaceInfo> interfaceInfoList = interfaceInfoService.list(queryWrapper);
        return ResultUtils.success(interfaceInfoList);
    }

    /**
     * 分页获取列表
     *
     * @param interfaceInfoQueryRequest
     * @param request
     * @return
     */
    @GetMapping("/list/page")
    public BaseResponse<Page<InterfaceInfo>> listInterfaceInfoByPage(InterfaceInfoQueryRequest interfaceInfoQueryRequest
            , HttpServletRequest request) {
        // 判断参数信息是否有效
        if (interfaceInfoQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 创建一个接口对像
        InterfaceInfo interfaceInfoQuery = new InterfaceInfo();
        // 将参数信息复制给新创建的接口对象
        BeanUtils.copyProperties(interfaceInfoQueryRequest, interfaceInfoQuery);

        long current = interfaceInfoQueryRequest.getCurrent();
        long size = interfaceInfoQueryRequest.getPageSize();
        String sortField = interfaceInfoQueryRequest.getSortField();
        String sortOrder = interfaceInfoQueryRequest.getSortOrder();
        String description = interfaceInfoQuery.getDescription();
        // content 需支持模糊搜索
        interfaceInfoQuery.setDescription(null);
        // 限制爬虫
        if (size > 50) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        QueryWrapper<InterfaceInfo> queryWrapper = new QueryWrapper<>(interfaceInfoQuery);
        queryWrapper.like(StringUtils.isNotBlank(description), "description", description);
        queryWrapper.orderBy(StringUtils.isNotBlank(sortField),
                sortOrder.equals(CommonConstant.SORT_ORDER_ASC), sortField);
        Page<InterfaceInfo> interfaceInfoPage = interfaceInfoService.page(new Page<>(current, size), queryWrapper);
        return ResultUtils.success(interfaceInfoPage);
    }

    /**
     * 发布 仅管理员可以使用
     *
     * @param idRequest 参数信息，只需要接口id即可。
     * @param request
     * @return
     */
    @PostMapping("/online")
    @AuthCheck(mustRole = "admin")
    public BaseResponse<Boolean> onlineInterfaceInfo(@RequestBody IdRequest idRequest,
                                                     HttpServletRequest request) {

        // 判断请求参数是否有效
        if (idRequest == null || idRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        long id = idRequest.getId();
        // 判断接口是否存在
        InterfaceInfo oldInterfaceInfo = interfaceInfoService.getById(id);
        if (oldInterfaceInfo == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        // 判断该接口是否可以调用
        com.mzw.mzwclientsdk.model.User user = new com.mzw.mzwclientsdk.model.User();
        user.setUsername("test");
        // 使用测试接口
        String username = mzwClient.getUsernameByPost(user);
        if (StringUtils.isBlank(username)) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "接口验证失败");
        }
        // 仅本人或者管理员可以修改，注解已经解决
        InterfaceInfo interfaceInfo = new InterfaceInfo();
        interfaceInfo.setId(id);
        interfaceInfo.setStatus(InterfaceInfoStatusEnum.ONLINE.getValue());
        boolean result = interfaceInfoService.updateById(interfaceInfo);
        return ResultUtils.success(result);
    }

    /**
     * 下线
     *
     * @param idRequest 请求信息
     * @param request
     * @return
     */
    @PostMapping("/offline")
    @AuthCheck(mustRole = "admin")
    public BaseResponse<Boolean> offlineInterfaceInfo(@RequestBody IdRequest idRequest,
                                                      HttpServletRequest request) {
        if (idRequest == null || idRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        long id = idRequest.getId();
        // 判断是否存在
        InterfaceInfo oldInterfaceInfo = interfaceInfoService.getById(id);
        if (oldInterfaceInfo == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        // 仅本人或者管理员可以修改
        InterfaceInfo interfaceInfo = new InterfaceInfo();
        interfaceInfo.setId(id);
        interfaceInfo.setStatus(InterfaceInfoStatusEnum.OFFLINE.getValue());
        boolean result = interfaceInfoService.updateById(interfaceInfo);
        return ResultUtils.success(result);
    }

    /**
     * 测试调用
     *
     * @param interfaceInfoInvokeRequest
     * @param request
     * @return
     */
    @PostMapping("/invoke")
    public BaseResponse<Object> invokeInterfaceInfo(@RequestBody InterfaceInfoInvokeRequest interfaceInfoInvokeRequest,
                                                    HttpServletRequest request) {
        // 判断前端传过来的参数是否有效
        if (interfaceInfoInvokeRequest == null || interfaceInfoInvokeRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 获取接口id
        Long id = interfaceInfoInvokeRequest.getId();
        String userRequestParams = interfaceInfoInvokeRequest.getUserRequestParams();

        // 判断接口是否存在
        InterfaceInfo oldInterfaceInfo = interfaceInfoService.getById(id);
        if (oldInterfaceInfo == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        // 判断接口状态
        if (oldInterfaceInfo.getStatus() == InterfaceInfoStatusEnum.OFFLINE.getValue()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "接口已关闭");
        }
        // 拿到登录用户的信息
        User loginUser = userService.getLoginUser(request);
        String accessKey = loginUser.getAccessKey();
        String secretKey = loginUser.getSecretKey();

        MzwClient tempClient = new MzwClient(accessKey, secretKey); // 如果不设置这样，那么一直用的就是配置里面的数据
        // 直接存入参数即可
        Word word = JSONUtil.toBean(userRequestParams, Word.class);

        String translation = tempClient.getTranslation(word);
        return ResultUtils.success(translation);
    }


    /**
     * 根据 Zset 获取接口次数排行榜
     *
     * @return
     */
    @GetMapping("/ranking")
    public BaseResponse<List<InterfaceInfoRankRequest>> queryRankInterfaceInfo() {
        String key = "interfaceInfoId";
        // 查询排名前10
        Set<String> top10 = stringRedisTemplate.opsForZSet().reverseRange(key, 0, 9);
        if (top10 == null || top10.isEmpty()) {
            return ResultUtils.success(Collections.emptyList());
        }
        // 对得到的接口集合进行处理
        List<Long> ids = top10.stream().map(Long::valueOf).collect(Collectors.toList());
        String idStr = StrUtil.join(",", ids);
        // 根据id去查询接口
        List<InterfaceInfoRankRequest> infoRank = interfaceInfoService.query().in("id", ids).last("ORDER BY FIELD(id," + idStr + ")").list()
                .stream()
                .map(interfaceInfo -> BeanUtil.copyProperties(interfaceInfo, InterfaceInfoRankRequest.class))
                .collect(Collectors.toList());
        return ResultUtils.success(infoRank);
    }

    /**
     * 推荐歌曲接口
     * @param interfaceInfoInvokeRequest
     * @param request
     * @return
     */
    @PostMapping("/songname")
    public BaseResponse<Object> getSongNameInterfaceInfo(@RequestBody InterfaceInfoInvokeRequest interfaceInfoInvokeRequest,
                                                         HttpServletRequest request) {
        // 判断前端传过来的参数是否有效
        if (interfaceInfoInvokeRequest == null || interfaceInfoInvokeRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 获取接口id
        Long id = interfaceInfoInvokeRequest.getId();
        String userRequestParams = interfaceInfoInvokeRequest.getUserRequestParams();

        // 判断接口是否存在
        InterfaceInfo oldInterfaceInfo = interfaceInfoService.getById(id);
        if (oldInterfaceInfo == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        // 判断接口状态
        if (oldInterfaceInfo.getStatus() == InterfaceInfoStatusEnum.OFFLINE.getValue()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "接口已关闭");
        }
        // 拿到登录用户的信息
        User loginUser = userService.getLoginUser(request);
        String accessKey = loginUser.getAccessKey();
        String secretKey = loginUser.getSecretKey();

        MzwClient tempClient = new MzwClient(accessKey, secretKey); // 如果不设置这样，那么一直用的就是配置里面的数据
        SongName songName = JSONUtil.toBean(userRequestParams, SongName.class);
        String names = tempClient.getSongName(songName);
        return ResultUtils.success(names); // 返回 post名字是。。。
    }


    /**
     * 翻译接口
     * @param interfaceInfoInvokeRequest
     * @param request
     * @return
     */
    @PostMapping("/translation")
    public BaseResponse<Object> getTranslationInterfaceInfo(@RequestBody InterfaceInfoInvokeRequest interfaceInfoInvokeRequest,
                                                        HttpServletRequest request) {
        // 判断前端传过来的参数是否有效
        if (interfaceInfoInvokeRequest == null || interfaceInfoInvokeRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 获取接口id
        Long id = interfaceInfoInvokeRequest.getId();
        String userRequestParams = interfaceInfoInvokeRequest.getUserRequestParams();

        // 判断接口是否存在
        InterfaceInfo oldInterfaceInfo = interfaceInfoService.getById(id);
        if (oldInterfaceInfo == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        // 判断接口状态
        if (oldInterfaceInfo.getStatus() == InterfaceInfoStatusEnum.OFFLINE.getValue()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "接口已关闭");
        }
        // 拿到登录用户的信息
        User loginUser = userService.getLoginUser(request);
        String accessKey = loginUser.getAccessKey();
        String secretKey = loginUser.getSecretKey();

        MzwClient tempClient = new MzwClient(accessKey, secretKey); // 如果不设置这样，那么一直用的就是配置里面的数据
        // 直接存入参数即可
        Word word = JSONUtil.toBean(userRequestParams, Word.class);

        String translation = tempClient.getTranslation(word);
        return ResultUtils.success(translation);
    }

    /**
     * 生成土味情话接口
     * @param interfaceInfoInvokeRequest
     * @param request
     * @return
     */
    @PostMapping("/words")
    public BaseResponse<Object> getLoveWordsInterfaceInfo(@RequestBody InterfaceInfoInvokeRequest interfaceInfoInvokeRequest,
                                                            HttpServletRequest request) {
        // 判断前端传过来的参数是否有效
        if (interfaceInfoInvokeRequest == null || interfaceInfoInvokeRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 获取接口id
        Long id = interfaceInfoInvokeRequest.getId();
        String userRequestParams = interfaceInfoInvokeRequest.getUserRequestParams();
        userRequestParams = "{\"message\":\"\"}";

        // 判断接口是否存在
        InterfaceInfo oldInterfaceInfo = interfaceInfoService.getById(id);
        if (oldInterfaceInfo == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        // 判断接口状态
        if (oldInterfaceInfo.getStatus() == InterfaceInfoStatusEnum.OFFLINE.getValue()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "接口已关闭");
        }
        // 拿到登录用户的信息
        User loginUser = userService.getLoginUser(request);
        String accessKey = loginUser.getAccessKey();
        String secretKey = loginUser.getSecretKey();

        MzwClient tempClient = new MzwClient(accessKey, secretKey); // 如果不设置这样，那么一直用的就是配置里面的数据
        // 直接存入参数即可
        Message message = JSONUtil.toBean(userRequestParams, Message.class);

        String result = tempClient.getLoveWords(message);
        return ResultUtils.success(result);
    }
}